/**
 * \file    transaction.h
 * \brief   Helps to build the action table from a generator.
 * \author  Jérôme LAURENS
 * \version 0.1
 * \date    November 20, 2014
 *
 * Reads a LALR(1) grammar, generates a parser based on a template file.
 * This is based on lemon parser generator, but has strongly been
 * revisited.
 *
 */

#ifndef TRANSACTION_H
#define TRANSACTION_H

#include "common.h"

LPP_NAMESPACE_BEGIN

/*
** The state of the yy_action table under construction is an instance of
** the expected_symbolsing structure.
**
** The yy_action table maps the pair (state_number, lookahead) into an
** action_number.  The table is an array of integers pairs.  The state_number
** determines an initial offset into the yy_action array.  The lookahead
** value is then added to this initial offset to get an index X into the
** yy_action array. If the action_table_m[X].lookahead equals the value of the
** of the lookahead input, then the value of the action_number output is
** action_table_m[X].action.  If the lookaheads do not match then the
** default action for the state_number is returned.
**
** All actions associated with a single state_number are first entered
** into transaction sets using multiple calls to add_transaction().  Then the
** transactions for that single state_number are inserted into the action_table_m[]
** array with a single call to insert_transactions().
*/
class Transaction {
public:
    Transaction(SymbolIndex const __l, ActionIndex const __a)
        : lookahead_m(__l)
        , action_m(__a) {};
    SymbolIndex lookahead() const {
        return lookahead_m;   /* Value of the lookahead token */
    }
    ActionIndex action() const {
        return action_m;      /* Action to take on the given lookahead */
    }
    bool operator==(Transaction const & rhs) const {
        return lookahead_m==rhs.lookahead_m && action_m==rhs.action_m;
    }
    bool operator!=(Transaction const & rhs) const {
        return !(*this==rhs);
    }
    bool operator<(Transaction const & rhs) const {
        return lookahead_m<rhs.lookahead_m
                || ( lookahead_m == rhs.lookahead_m
                && action_m<rhs.action_m );
    }
private:
    SymbolIndex lookahead_m;   /* Value of the lookahead token */
    ActionIndex action_m;      /* Action to take on the given lookahead */
};

typedef std::map<Index,Transaction> Transactions;
typedef std::deque<Transaction> TransactionList;

class TransactionSet {
public:
    typedef Transactions::size_type Size;
    TransactionSet()
        : min_transaction_m(std::numeric_limits<SymbolIndex>().max()
                        ,std::numeric_limits<ActionIndex>().max())
        , max_lookahead_m(std::numeric_limits<SymbolIndex>().min())
    {}
    TransactionList transactions() const {
        return transactions_m;
    }
    Transaction min() const {
        return min_transaction_m;
    }
    SymbolIndex amplitude() const {
        if (max_lookahead()<min_lookahead()) {
            throw std::logic_error("Void transaction sets have no amplitude.");
        }
        return max_lookahead()-min_lookahead();
    }
    SymbolIndex min_lookahead() const {
        return min_transaction_m.lookahead();   /* Minimum transactions_m[].lookahead */
    }
    SymbolIndex max_lookahead() const {
        return max_lookahead_m;         /* Maximum transactions_m[].lookahead */
    }
    void add_transaction(ActionRef const & action, SymbolIndex const lookahead, ActionCode const code);
    Size size() const {
        return transactions_m.size();
    }
private:
    TransactionList transactions_m;
    Transaction min_transaction_m;
    SymbolIndex max_lookahead_m;         /* [Maximum transactions_m[].lookahead] */
};

bool operator== (TransactionSet const & lhs, TransactionSet const & rhs);

LPP_NAMESPACE_END

#endif // TRANSACTION_H
